﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Protocol;
using System.IO;

namespace MDS
{
    public class ShenzhenDBFQuotationProvider : DBFQuotationProviderBase
    {
        static List<StockExchange> _exchanges = new List<StockExchange>() { StockExchange.ShenA, StockExchange.ShenB };
        private TradeRulesConfig _tradeRulesConfig;
        private IInterestProvider _interestProvider;
        private ShenzhenExtInfoProvider _extInfoProvider;

        #region 构造函数
        public ShenzhenDBFQuotationProvider(
            DBFQuotationProviderConfig config,
            TradeRulesConfig tradeRulesConfig,
            IInterestProvider interestProvider,
            ShenzhenExtInfoProvider extInfoProvider)
            : base(config)
        {
            this._tradeRulesConfig = tradeRulesConfig;
            this._interestProvider = interestProvider;
            this._extInfoProvider = extInfoProvider;
        }

        #endregion



        protected override bool tryReadDbfFile(string fileName,
          out IEnumerable<IMessage> messages,
          out DateTime? tradeTime)
        {
            DateTime dt;
            IList<SJSHQDBFRecord> records;
            try
            {
                read(fileName, out records, out dt);
                //TODO:可能还要加交易日判断
                if (this._lastTradeTime.HasValue
                    && this._lastTradeTime.Value > dt)
                {
                    messages = null;
                    tradeTime = this._lastTradeTime;
                    return false;
                }
                else
                {
                    messages = buildMessages(records, dt);
                    tradeTime = dt;
                }
                return true;
            }
            catch (Exception ex)
            {
                Log.Debug(ex);
                messages = null;
                tradeTime = this._lastTradeTime;
                return false;
            }
        }
        private void read(string fileName, out IList<SJSHQDBFRecord> records, out DateTime tradeTime)
        {
            List<SJSHQDBFRecord> rtn = new List<SJSHQDBFRecord>();
            FileStream dbfileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            byte[] fileBuffer = new byte[dbfileStream.Length];
            dbfileStream.Read(fileBuffer, 0, (int)dbfileStream.Length);
            dbfileStream.Close();
            rtn = DBFHelper.ReadRecords<SJSHQDBFRecord>(fileBuffer);
            pickupTradeTimeRecord(rtn, out tradeTime);
            records = rtn;
        }

        private void pickupTradeTimeRecord(List<SJSHQDBFRecord> records, out DateTime tradeTime)
        {

            tradeTime = default(DateTime);
            if (records.Any(r => r.StkId == "000000"))
            {
                var tradeTimeRecord = records.Where(r => r.StkId == "000000").FirstOrDefault();
                records.Remove(tradeTimeRecord);
                string dateStr = tradeTimeRecord.StkName;
                string timeStr = tradeTimeRecord.TradesCount.ToString("000000");
                //TODO:字符串转日期
            }

        }


        private IEnumerable<IMessage> buildMessages(IList<SJSHQDBFRecord> records, DateTime tradeTime)
        {
            List<Protocol.IMessage> rtn = new List<IMessage>();
            for (int i = 0; i < records.Count; i++)
            {
                if (records[i].StkId.Length != 6
                    || isSuspend (records[i]))
                    continue;
               

                var basicInfo = buildBasicInfo(records[i]);
                rtn.Add(basicInfo);

                if (basicInfo.SuspendedFlag == SuspendedFlag.True)
                    continue;

                var bid = buildBid(records[i], tradeTime);
                rtn.Add(bid);
                if (i < records.Count - 1)
                {
                    var tick = buildTick(records[i], tradeTime, bid, records[i + 1]);
                    if (tick != null)
                        rtn.Add(tick);
                }
                else
                {
                    var tick = buildTick(records[i], tradeTime, bid, null);
                    if (tick != null)
                        rtn.Add(tick);
                }
            }
            return rtn;
        }

        /// <summary>
        /// 判断是否属于连续停牌
        /// </summary>
        /// <param name="record"></param>
        /// <returns></returns>
        /// TODO:还要加上当前时间与开盘时间的对比
        private bool isSuspend(SJSHQDBFRecord record)
        {
            if (record.OpenPrice <= 0)
                return true;
            else
                return false;
        }


        private GWMKTBasicInfoANS buildBasicInfo(SJSHQDBFRecord record)
        {
            GWMKTBasicInfoANS basicInfo = new GWMKTBasicInfoANS();

            basicInfo.StkID = record.StkId;




            //TODO:可加Dic缓存结果
            StockExchange exch = this._tradeRulesConfig.GetStockExchange(record.StkId, _exchanges);
            if (exch==null)
                exch = _exchanges[0];
            basicInfo.ExchID =(char) exch;

            TradeType tradeType = this._tradeRulesConfig.GetStockTradeType(record.StkId, _exchanges);
            if (tradeType == default(TradeType))
                tradeType = TradeType.正常买卖;
            basicInfo.TradeType = (string)tradeType;

            StkType stkType = this._tradeRulesConfig.GetStkType(record.StkId, _exchanges);
            if (stkType == default(StkType))
                stkType = StkType.Equity;
            basicInfo.StkType = (string)stkType;



            basicInfo.StkName = record.StkName;
            if (!string.IsNullOrEmpty(record.StkName))
            {

                if (record.StkName.Contains("暂停"))
                {
                    basicInfo.SuspendedFlag = (char)SuspendedFlag.True;
                }

                if (record.StkName[0]=='N')
                {
                    basicInfo.TradeStatus = (char)TradeStatus.Y;

                    //TODO:是否应该是当前交易日，而不是DateTime.Now
                    basicInfo.BeginDate = Int64.Parse(DateTime.Now.ToString("yyyyMMddHHmmss"));
                }
                else
                {
                    basicInfo.TradeStatus = 'N';
                }
            }
            else
            {
                basicInfo.TradeStatus = 'N';
            }

            basicInfo.Closeprice = record.ClosePrice;
            basicInfo.OpenPrice = record.OpenPrice;


            StockTradeRule tradeRule = this._tradeRulesConfig.GetStockTradeRule(record.StkId, _exchanges);
            if (tradeRule != null)
            {
                basicInfo.HighBuyQtyLimit = tradeRule.BuyHighLimit;
                basicInfo.LowBuyQtyLimit = tradeRule.BuyLowerLimit;
                basicInfo.HighSellQtyLimit = tradeRule.SellHighLimit;
                basicInfo.LowSellQtyLimit = tradeRule.SellLowerLimit;
                basicInfo.OrderPriceUnit = tradeRule.OrderPriceUnit;
                basicInfo.ParValue = tradeRule.StockParValue;
                basicInfo.Decimal = tradeRule.Decimal;
                basicInfo.convertQty = tradeRule.ConvertQty;
                basicInfo.TradeUnit = tradeRule.TradeUnit;
                basicInfo.StkDeliveryDays = (short)tradeRule.StkDeliveryDays;
            }
            else
            {
                Log.Debug(string.Format("未找到交易规则，StkId={0}", record.StkId));
            }


            if (stkType==StkType.Bond)
            {
                basicInfo.MaxOrderPrice = 99999.99;
                basicInfo.MinOrderPrice = 0;
                basicInfo.AccuredInterest = this._interestProvider.GetAccuredInterest(record.StkId);
                if (basicInfo.Decimal != null && basicInfo.AccuredInterest != null)
                {
                    basicInfo.AccuredInterest = StockAmount.Round(basicInfo.AccuredInterest.Value, basicInfo.Decimal.Value);
                }
            }
            else
            {
                StockHelper.CalculateMaxAndMinOrderPrice(basicInfo);

            }
            StockHelper.FormatAmount(basicInfo);




            basicInfo.StkIndustryType = this._extInfoProvider.GetStkIndustryType(record.StkId);
            basicInfo.TotalCirculatingShare = this._extInfoProvider.GetTotalCirculatingShare(record.StkId);
            basicInfo.SuspendedFlag =(char) this._extInfoProvider.GetSuspendedFlag(record.StkId);
            basicInfo.TotalIssueQty = this._extInfoProvider.GetTotalIssueQty(record.StkId);
            basicInfo.MaxOrderPrice = this._extInfoProvider.GetMaxOrderPrice(record.StkId);
            basicInfo.MinOrderPrice = this._extInfoProvider.GetMinOrderPrice(record.StkId);
            if (basicInfo.Decimal != null && basicInfo.Decimal.Value > 0)
            {
                basicInfo.MaxOrderPrice = StockAmount.Round(basicInfo.MaxOrderPrice, basicInfo.Decimal);
                basicInfo.MinOrderPrice = StockAmount.Round(basicInfo.MinOrderPrice, basicInfo.Decimal);
            }
            basicInfo.TradeStatus = (char)this._extInfoProvider.GetTradeStatus(record.StkId);

            if (basicInfo.TradeStatus == (char)TradeStatus.Y)
            {
                basicInfo.MaxOrderPrice = 99999.999;
                basicInfo.MinOrderPrice = 0;
                basicInfo.BeginDate = Int64.Parse(DateTime.Now.ToString("yyyyMMddHHmmss"));
            }
            if (basicInfo.MaxOrderPrice == 0)
            {
                basicInfo.MaxOrderPrice = 0.1;
            }
            basicInfo.StkID = exch + record.StkId;


            return basicInfo;
        }

        private GWMKTBidAskANS buildBid(SJSHQDBFRecord record, DateTime tradeTime)
        {
            GWMKTBidAskANS bidAsk = new GWMKTBidAskANS();

            StockExchange exch = this._tradeRulesConfig.GetStockExchange(record.StkId, _exchanges);
            if (exch==null)
                exch = _exchanges[0];

            bidAsk.StkID = exch + record.StkId;
            bidAsk.BuyPrice1 = record.BuyPrice1;
            bidAsk.SellPrice1 = record.SellPrice1;
            bidAsk.BuyQty1 = record.BuyQty1;
            bidAsk.BuyPrice2 = record.BuyPrice2;
            bidAsk.BuyQty2 = record.BuyQty2;
            bidAsk.BuyPrice3 = record.BuyPrice3;
            bidAsk.BuyQty3 = record.BuyQty3;
            bidAsk.SellQty1 = record.SellQty1;
            bidAsk.SellPrice2 = record.SellPrice2;
            bidAsk.SellQty2 = record.SellQty2;
            bidAsk.SellPrice3 = record.SellPrice3;
            bidAsk.SellQty3 = record.SellQty3;
            bidAsk.BuyPrice4 = record.BuyPrice4;
            bidAsk.BuyQty4 = record.BuyQty4;
            bidAsk.BuyPrice5 = record.BuyPrice5;
            bidAsk.BuyQty5 = record.BuyQty5;
            bidAsk.SellPrice4 = record.SellPrice4;
            bidAsk.SellQty4 = record.SellQty4;
            bidAsk.SellPrice5 = record.SellPrice5;
            bidAsk.SellQty5 = record.SellQty5;
            bidAsk.OccurTime = Int64.Parse(tradeTime.ToString("yyyyMMddHHmmss"));


            //不知道是否需要
            //StkType stkType = this._tradeRulesConfig.GetStkType(record.StkId, _exchanges);
            //if (stkType.Equals(default(StkType)))
            //    stkType = StkType.Equity;

            //if (stkType.Equals(StkType.Bond))
            //{
            //    StockTradeRule tradeRule = this._tradeRulesConfig.GetStockTradeRule(record.StkId, _exchanges);
            //    if (tradeRule != null)
            //        StockHelper.FormatAmount(bidAsk, tradeRule);
            //}
            return bidAsk;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="record"></param>
        /// <param name="tradeTime"></param>
        /// <param name="bid"></param>
        /// <param name="nextRecord"></param>
        /// <returns></returns>
        /// TODO:刚复制过来，还没改
        private GWMKTTicksANS buildTick(
            SJSHQDBFRecord record,
            DateTime tradeTime,
            GWMKTBidAskANS bid,
            SJSHQDBFRecord? nextRecord)
        {
            GWMKTTicksANS tick = new GWMKTTicksANS();

            StockExchange exch = this._tradeRulesConfig.GetStockExchange(record.StkId, _exchanges);
            if (exch==null)
                exch = _exchanges[0];
            tick.StkID = exch + record.StkId;
            tick.KnockTime = Int64.Parse(tradeTime.ToString("yyyyMMddHHmmss"));
            tick.KnockPrice = record.KnockPrice;
            tick.TradesCount = record.TradesCount;
            tick.HighPrice = record.HighPrice;
            tick.Lowprice = record.LowPrice;
            tick.IOPV = record.PriceEarningRatio;

            StkType stkType = this._tradeRulesConfig.GetStkType(record.StkId, _exchanges);
            if (stkType==null)
                stkType = StkType.Equity;
            StockTradeRule tradeRule = this._tradeRulesConfig.GetStockTradeRule(record.StkId, _exchanges);

            //if (stkType.Equals(StkType.ETF)
            //    || stkType.Equals(StkType.Fund)
            //    || stkType.Equals(StkType.OTCFund))
            //{
            //    tick.IOPV = record.IOPV;
            //}


            //GWMKTTicksANS preTick = this.getTickInSnapshot(record.StkId);

            //StockHelper.FormatTickAvgPrice(tick, stkType, bid, tradeRule, preTick);
            //if (preTick != null)
            //{
            //    if (preTick.MktKnockQty != null)
            //    {
            //        tick.TotalMktKnockQty = record.TotalMktKnockQty;
            //        if (stkType.Equals(StkType.Bond) && tradeRule != null)
            //        {
            //            tick.TotalMktKnockQty = record.TotalMktKnockQty * tradeRule.ConvertQty;
            //        }
            //        if (tick.TotalMktKnockQty < preTick.TotalMktKnockQty)
            //            return null;
            //        tick.MktKnockQty = tick.TotalMktKnockQty - preTick.TotalMktKnockQty;
            //    }

            //    if (preTick.KnockAmt != null)//？？
            //    {
            //        tick.TotalMktKnockAmt = record.TotalMktKnockAmt;
            //        tick.KnockAmt = tick.TotalMktKnockAmt - preTick.TotalMktKnockAmt;
            //    }

            //}
            //else//初次构建
            //{
                tick.TotalMktKnockQty = record.TotalMktKnockQty;
                if (stkType==StkType.Bond && tradeRule != null)
                {
                    tick.TotalMktKnockQty = record.TotalMktKnockQty * tradeRule.ConvertQty;
                }
                tick.MktKnockQty = tick.TotalMktKnockQty;
                tick.TotalMktKnockAmt = record.TotalMktKnockAmt;
                tick.KnockAmt = tick.TotalMktKnockAmt;
            //}

            if (tradeRule != null)
            {
                tick.TotalMktKnockAmt = StockAmount.Round(tick.TotalMktKnockAmt, tradeRule.Decimal);
                tick.KnockAmt = StockAmount.Round(tick.KnockAmt, tradeRule.Decimal);
            }

            if (tick.MktKnockQty == 0)
            {
                return null;
            }
            else
            {
                return tick;
            }
        }
    }
}
